package com.leon.hom.http;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.leon.hom.core.common.Constants;
import com.leon.hom.http.entity.ErrorResult;
import com.leon.hom.http.entity.HttpRequestParam;
import com.leon.hom.http.entity.HttpResponseParam;
import io.netty.handler.codec.http.HttpVersion;
import okhttp3.*;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;


public class HttpClient {

    private final OkHttpClient client;

    private final String redirect;

    public HttpClient(String redirect) {
        this.client = new OkHttpClient();
        this.redirect = redirect;
    }

    public void doRequest(HttpRequestParam httpRequestParam, Consumer<HttpResponseParam> consumer) {

        String url = String.format("%s:%s%s", redirect, httpRequestParam.getTargetPort(), httpRequestParam.getUri());

        Request.Builder builder = new Request.Builder().url(url);

        String type = Constants.NULL;
        Map<String, String> headers = httpRequestParam.getHeaders();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            builder.addHeader(entry.getKey(), entry.getValue());
            if (entry.getKey().equals(Constants.CONTENT_TYPE)) {
                type = entry.getValue();
            }
        }

        RequestBody requestBody = null;
        if (!StrUtil.isEmpty(httpRequestParam.getBody())) {
            requestBody = RequestBody.create(MediaType.get(type), httpRequestParam.getBody());
        }
        builder.method(httpRequestParam.getMethod(), requestBody);

        Call call = client.newCall(builder.build());
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ErrorResult errorResult = new ErrorResult("Agent request failed", e.getMessage());

                HttpResponseParam responseParam = new HttpResponseParam();
                responseParam.setVersion(HttpVersion.HTTP_1_1.toString());
                responseParam.setCode(500);
                responseParam.setSourceTag(httpRequestParam.getTargetTag());
                responseParam.setTargetTag(httpRequestParam.getSourceTag());
                responseParam.setSourcePort(httpRequestParam.getSourcePort());
                responseParam.setTargetPort(httpRequestParam.getTargetPort());
                responseParam.setSessionId(httpRequestParam.getSessionId());
                responseParam.setBody(JSONUtil.toJsonStr(errorResult));

                DateFormat gmt = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.ENGLISH);
                gmt.setTimeZone(TimeZone.getTimeZone("GMT"));

                HashMap<String, String> headerMap = new HashMap<>();
                headerMap.put("Transfer-Encoding", "chunked");
                headerMap.put("Content-Type", "application/json");
                headerMap.put("Date", gmt.format(new Date()));
                responseParam.setHeaders(headerMap);

                consumer.accept(responseParam);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                HttpResponseParam responseParam = new HttpResponseParam();
                responseParam.setVersion(response.protocol().toString());
                responseParam.setCode(response.code());
                responseParam.setSourceTag(httpRequestParam.getTargetTag());
                responseParam.setTargetTag(httpRequestParam.getSourceTag());
                responseParam.setSourcePort(httpRequestParam.getSourcePort());
                responseParam.setTargetPort(httpRequestParam.getTargetPort());
                responseParam.setSessionId(httpRequestParam.getSessionId());
                ResponseBody body = response.body();
                if (null != body) {
                    responseParam.setBody(new String(body.bytes()));
                }

                Headers headers = response.headers();
                Set<String> names = headers.names();
                HashMap<String, String> headerMap = new HashMap<>();
                for (String name : names) {
                    headerMap.put(name, headers.get(name));
                }

                responseParam.setHeaders(headerMap);
                consumer.accept(responseParam);
            }
        });

    }


}
